package com.lx.util;//说明:

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * 创建人:游林夕/2019/3/29 14 57
 */
public class LXLog {

    private LXLog(){
    }
    private static final ThreadLocal<Map<String, Object>> tl = ThreadLocal.withInitial(() -> new HashMap(4));
    public static  <T>T get(String key){
        return (T) tl.get().get(key);
    }
    public static void put(String key,Object obj){
        tl.get().put(key,obj);
    }
    public static void remove(){
        tl.remove();
    }

    private static PrintWriter pw;
    private static String fileName ;
    private static SimpleDateFormat sdf=new SimpleDateFormat("'logs/'yyyy-MM-dd'.log'");
    private static SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
    //%p: 输出日志信息优先级，即DEBUG，INFO，WARN，ERROR，FATAL,
    //%d: 输出日志时间点的日期或时间，默认格式为ISO8601，也可以在其后指定格式，比如：%d{yyyy-MM-dd HH:mm:ss,SSS}，输出类似：2011-10-18 22:10:28,921
    //%c: 输出日志信息所属的类目，通常就是所在类的全名
    //%t: 输出产生该日志事件的线程名
    //%l: 输出代码中的行号
    //%m: 输出代码中指定的消息,产生的日志具体信息
    //%n: 输出一个回车换行符，Windows平台为"\r\n"，Unix平台为"\n"输出日志信息换行
    //%T: 输出线程id
    private static String pattern = "%d %p [T:%T %c:%l] %m%n";
    public static void info(Object msg){
        printP(msg.toString());
    }
    public static void debug(Object msg){
        printP(msg.toString());
    }
    public static void error(String msg, Exception err){
        printP(msg);
        printE(err);
    }
    static void printP(String msg){
        if (LX.isEmpty(msg)||LX.isEmpty(pattern))return;
        String s = pattern;
        StackTraceElement[] se = Thread.currentThread().getStackTrace();
        if (get("MDC")==null){
            put("MDC",LX.uuid32(10));
        }
        s=s.replace("%p",left(se[2].getMethodName().toUpperCase(),6))
                .replace("%d",sdf1.format(new Date()))
                .replace("%c",se[3].getClassName())
                .replace("%l",""+se[3].getLineNumber())
                .replace("%t",Thread.currentThread().getName())
                .replace("%T",(String)get("MDC"))
                .replace("%n", "\r\n")
                .replace("%m",msg);
        print(s);
    }
    public static void printE(Exception e) {
        if (LX.isEmpty(e)||LX.isEmpty(pattern))return;
        String s = pattern;
        StackTraceElement[] se = Thread.currentThread().getStackTrace();
        put("MDC",get("MDC")==null?UUID.randomUUID().toString():get("MDC"));
        s=s.replace("%p",left(se[2].getMethodName().toUpperCase(),6))
                .replace("%d",sdf1.format(new Date()))
                .replace("%c", se[3].getClassName())
                .replace("%l",""+se[3].getLineNumber())
                .replace("%T",(String)get("MDC"))
                .replace("%n","\r\n")
                .replace("%m",e.getCause()!=null?e.getCause().getMessage():e.toString());
        print(s);
        print(e);
    }
    private static void print(Object msg){
        String file = sdf.format(new Date());
        try{
            if (fileName != file) pw = getPrintWriter((fileName=file));
        }catch (Exception e){
            if(pw!=null) pw.close();
            return;
        }
        if (msg instanceof Exception){
            ((Exception)msg).printStackTrace(pw);
        }else{
            pw.print(msg);
            System.out.print(msg);
        }
        pw.flush();
    }

    /**获取输出流*/
    private static PrintWriter getPrintWriter(String fileName) throws Exception {
        File file = new File(fileName);
        File fileParent = file.getParentFile();
        if (fileParent != null &&!fileParent.exists())fileParent.mkdirs();
        return new PrintWriter(new OutputStreamWriter(new FileOutputStream(file,true), "utf-8"),true);
    }


    /**左对齐*/
    public static String left(String str,int i){return str.length()>=i?str.substring(0,i):(str+new String(new byte[i])).substring(0,i);};
}
